/*Z ACPI(Advanced Configuration and Power Interface)替代了APM */

/*
 * Copyright 2014, General Dynamics C4 Systems
 *
 * SPDX-License-Identifier: GPL-2.0-only
 */

#pragma once

#include <assert.h>
#include <config.h>
#include <types.h>
/*Z ACPI-RSDP表结构的大小 */
enum acpi_size {
    ACPI_V1_SIZE = 20,
    ACPI_V2_SIZE = 36
};
/*Z ACPI有各种各样的SDT表，这是每个每都要包含的头。共36个字节 */
/* Generic System Descriptor Table Header */
typedef struct acpi_header {
    char         signature[4];
    uint32_t     length;            /*Z 该表(注意这里是个header)总大小，包括第二部分的entry项 */
    uint8_t      revision;
    uint8_t      checksum;          /*Z 该表所有字节加起来，低字节应为0 */
    char         oem_id[6];
    char         oem_table_id[8];
    uint32_t     oem_revision;
    char         creater_id[4];
    uint32_t     creater_revision;
} PACKED acpi_header_t;
/*Z RSDP是存储在0x80000-0x9FFFF或0xE0000-0xFFFFF内的ACPI基本信息。共36个字节 */
/* Root System Descriptor Pointer */
typedef struct acpi_rsdp {
    char         signature[8];      /*Z "RSD PTR "，无'\0'，起始地址16字节对齐 */
    uint8_t      checksum;          /*Z 成员length前所有字节加起来，低字节应为0 */
    char         oem_id[6];         /*Z 厂商 */
    uint8_t      revision;          /*Z 0-APCI版本1.0，1 - 2.0以上 */
    uint32_t     rsdt_address;      /*Z RSDT表物理地址，注意是32位 */
    uint32_t     length;            /*Z 从此开始是2.0版的扩展。整个结构的大小 */
    uint64_t     xsdt_address;      /*Z XSDT表物理地址，注意是64位。2.0以上版本使用此项，不用rsdt_address */
    uint8_t      extended_checksum; /*Z 同上，所有字段加起来 */
    char         reserved[3];
} PACKED acpi_rsdp_t;
compile_assert(acpi_rsdp_packed, sizeof(acpi_rsdp_t) == ACPI_V2_SIZE)
/*Z RSDT是各种具体SDT的总入口，这些SDT描述了各种设备电源、温度等的操作接口 */
/* Root System Descriptor Table *//*Z XSDT与此相同，只是entry为uint64_t。考虑向下兼容，此表意义不大 */
typedef struct acpi_rsdt {
    acpi_header_t  header;
    uint32_t entry[1];      /*Z 其它SDT的入口，注意这里数组长度实际与SDT数量一样 */
} PACKED acpi_rsdt_t;
/*Z 获取并保存RSDP表（在rsdp_data中），验证检验和。返回值1成功，0失败 */
/* Attemps to initialize acpi by searching for a valid RSDP block. If found a copy is placed in rsdp_data
 * and true is returned, otherwise the contents of rsdp_data are undefined and false is returned. */
bool_t acpi_init(acpi_rsdp_t *rsdp_data);
/*Z 验证RSDP、RSDT校验和 */
/* Validates that a given rsdp block is in fact valid */
BOOT_CODE bool_t acpi_validate_rsdp(acpi_rsdp_t *acpi_rsdp);

uint32_t acpi_madt_scan(
    acpi_rsdp_t *acpi_rsdp,
    cpu_id_t    *cpu_list,
    uint32_t    *num_ioapic,
    paddr_t     *ioapic_addrs
);
/*Z IOMMU管理下的用于老旧设备DMA的保留内存区 */
typedef struct acpi_rmrr_entry {
    dev_id_t device;/*Z PCI设备id（总线、设备、功能号）*/
    uint32_t base;  /*Z 起始物理地址，页对齐 */
    uint32_t limit; /*Z 结束地址(含)。页对齐-1 */
} acpi_rmrr_entry_t;
/*Z IOMMU管理下的用于老旧设备DMA的保留内存区列表，每设备一项 */
typedef struct acpi_rmrr_list {
    acpi_rmrr_entry_t entries[CONFIG_MAX_RMRR_ENTRIES];/*Z 老旧设备DMA保留内存区列表 */
    int num;    /*Z 列表项目数(设备数) */
} acpi_rmrr_list_t;

void acpi_dmar_scan(
    acpi_rsdp_t *acpi_rsdp,
    paddr_t     *drhu_list,
    uint32_t    *num_drhu,
    uint32_t     max_dhru_list_len,
    acpi_rmrr_list_t *rmrr_list
);

bool_t acpi_fadt_scan(
    acpi_rsdp_t *acpi_rsdp
);
